extern "C" 
{
	#include "lua.h"
	#include "lualib.h"
	#include "lauxlib.h"
};

#include <boost/bind.hpp>
#include <boost/function.hpp>

#include "lua_tinker.h"

#include "common.h"

#include "numbers.h"

#include "object.h"
#include "actor.h"
#include "pawn.h"
#include "actormanager.h"

#include "camera.h"
#include "tpvcamera.h"

#include "scene.h"
#include "scenemanager.h"

static void SetCamera( const char* sceneName, lua_tinker::table params )
{
	const char* name	= params.get< const char* >( "name" );
	D3DXVECTOR3 pos		= params.get< D3DXVECTOR3 >( "pos" );

	std::string type( params.get< const char* >( "type" ) );

	Camera* cam = NULL;
	if( type == "fpv" )
	{
	}

	if( type == "tpv" )
	{
		cam = new TpvCamera( name );

		D3DXVECTOR3 pos = params.get< D3DXVECTOR3 >( "pos" );
		D3DXVECTOR3 lookat = params.get< D3DXVECTOR3 >( "lookat" );

		Actor* pObj = Actor::Create( "CameraActor", "Objective" );
		Actor* pSub = Actor::Create( "CameraActor", "Subjective" );

		pObj->SetPosition( lookat );
		pSub->SetPosition( pos );

		cam->SetObjectiveTarget( pObj );
		cam->SetSubjectiveTarget( pSub );

	}

	Scene* pScene = Core::GetSceneManager().GetScene( sceneName );
	pScene->SetViewCamera( cam );
}

static void SetPawn( const char* sceneName, const char* typeName, const char* pawnName )
{
	Scene* pScene = Core::GetSceneManager().GetScene( sceneName );
	Pawn* pPawn = Pawn::Create( typeName, pawnName );
	pScene->AddActor( pPawn );
}

static void SetUI( const char* sceneName, lua_tinker::table params )
{
	UI* pUI = NULL;
	std::string type = params.get< const char* >( "type" );
	std::string name = params.get< const char* >( "name" );

	if( type == "Numbers" )
	{
		D3DXVECTOR2 pos	= params.get< D3DXVECTOR2 >( "pos" );
		int size		= params.get< int >( "size" );
		D3DXVECTOR3 c	= params.get< D3DXVECTOR3 >( "color" );

		Numbers* pNum = new Numbers( ( DWORD )pos.x, ( DWORD )pos.y );
		pNum->SetImage( L"./media/image/numbers.png" );
		pNum->SetSize( size );

		DWORD color = D3DCOLOR_ARGB( 255, (int)c.x, (int)c.y, (int)c.z );
		pNum->SetColor( color );

		pUI = pNum;
	}

	if( pUI == NULL )
	{
		assert( false );
		return;
	}

	Scene* pScene = Core::GetSceneManager().GetScene( sceneName );
	pScene->AddUI( name, pUI );
}

SceneManager::SceneManager()
:	_currentScene( NULL )
,	_L( NULL )
{
}

SceneManager::~SceneManager()
{
}

Scene* SceneManager::GetScene( const std::string& name )
{
	SceneListIter it = _lists.find( name );
	if( it != _lists.end() )
	{
		return it->second;
	}

	return NULL;
}

bool SceneManager::Initialize()
{
	lua_State* L = lua_open();
	luaopen_base( L );
	luaopen_string( L );

	lua_tinker::def( L, "ViewCamera", &SetCamera );
	lua_tinker::def( L, "Pawn", &SetPawn );
	lua_tinker::def( L, "UI", &SetUI );

	lua_tinker::class_add< D3DXVECTOR2 >( L, "float2" );
	lua_tinker::class_con< D3DXVECTOR2 >( L, lua_tinker::constructor< D3DXVECTOR2, float, float > );
	lua_tinker::class_add< D3DXVECTOR3 >( L, "float3" );
	lua_tinker::class_con< D3DXVECTOR3 >( L, lua_tinker::constructor< D3DXVECTOR3, float, float, float > );

	_L = L;
	return true;
}

void SceneManager::Release()
{
	SceneList::iterator it = _lists.begin();
	for( ; it != _lists.end(); ++it )
	{
		delete it->second;
	}
	_lists.clear();

	if( _L )
	{
		lua_close( _L );
		_L = NULL;
	}
	delete this;
}

void SceneManager::Register( const std::string& name, const std::string& path )
{
	if( GetScene( name ) != NULL )
	{
		return;
	}

	_lists[ name ] = new Scene;
	lua_tinker::dofile( _L, path.c_str() );
}

void SceneManager::SetCurrentScene( const std::string& name )
{
	Scene* scene = GetScene( name );
	if( scene == NULL )
	{
		return;
	}
	_currentScene = scene;
}

void SceneManager::Unregister( const std::string& name )
{
	if( _lists.find( name ) == _lists.end() )
	{
		return;
	}
	delete _lists[ name ];
}
